package com.kinghood.authoritycenter.service.impl;

import com.alibaba.nacos.common.utils.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kinghood.authoritycenter.common.model.dao.authority.AuthorityMenuApiRelateDO;
import com.kinghood.authoritycenter.common.model.dao.authority.AuthorityMenuDO;
import com.kinghood.authoritycenter.common.model.dao.authority.AuthorityRoleMenuRelateDO;
import com.kinghood.authoritycenter.common.model.dto.authority.*;
import com.kinghood.authoritycenter.common.model.serviceimpl.AuthorityMenuApiRelateServiceImpl;
import com.kinghood.authoritycenter.common.model.vo.authority.GetMenuVO;
import com.kinghood.authoritycenter.common.util.UserUtil;
import com.kinghood.authoritycenter.dao.authority.AuthorityMenuApiRelateMapper;
import com.kinghood.authoritycenter.dao.authority.AuthorityMenuMapper;
import com.kinghood.authoritycenter.service.IAuthorityMenuService;
import com.kinghood.infrastructure.model.KingHoodExceptionUtil;
import com.kinghood.infrastructure.model.constant.CommonConstants;
import com.kinghood.authoritycenter.common.model.dto.auth.UserDTO;
import com.kinghood.infrastructure.util.base.IdGenUtil;
import com.kinghood.sharding.model.KingHoodPageUtil;
import com.kinghood.sharding.model.KingPageResult;
import com.kinghood.sharding.model.PageResponseVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统菜单表 服务实现类
 * </p>
 *
 * @author KingHood
 * @since 2023-12-18
 */
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class)
@Slf4j
@Service
public class AuthorityMenuServiceImpl extends ServiceImpl<AuthorityMenuMapper, AuthorityMenuDO> implements IAuthorityMenuService {

    private final AuthorityMenuApiRelateServiceImpl menuApiRelateService;

    @Override
    public PageResponseVO<AuthorityMenuDO> queryPageByParentId(MenuQueryPageReqDTO in) {

        Page<AuthorityMenuDO> page = this.baseMapper.queryPageByParentId(KingHoodPageUtil.getPage(in, in), in);
        return KingPageResult.getResult(page);
    }

    @Override
    public AuthorityMenuDO addMenu(AddMenuReqDTO in) {
        // 角色名字和code重复
        long count = new LambdaQueryChainWrapper<>(this.getBaseMapper())
                .eq(AuthorityMenuDO::getPermissionCode, in.getPermissionCode())
                .eq(AuthorityMenuDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .count();
        KingHoodExceptionUtil.trueThrows(count > 0, "菜单code已存在");

        String idPath = null;
        if(Objects.nonNull(in.getParentId())){
            GetMenuVO parent = getMenu(in.getParentId());
            KingHoodExceptionUtil.isNull(parent,"父类不存在");
            idPath = parent.getIdPath();
            KingHoodExceptionUtil.isNull(idPath,"父类idPath存在异常");
        }

        AuthorityMenuDO one = new AuthorityMenuDO();
        BeanUtils.copyProperties(in, one);
        UserDTO user = UserUtil.getUser();
        Date now = new Date();
        one.setCreateTime(now);
        one.setUpdateTime(now);
        one.setCreateUserId(UserUtil.getUserId());
        one.setUpdateUserId(UserUtil.getUserId());
        one.setId(IdGenUtil.get().nextId());
        if(idPath == null){
            one.setIdPath(one.getId().toString());
            one.setLevel(1);
        } else {
            one.setIdPath(idPath + "/" + one.getId().toString() );
            one.setLevel(one.getIdPath().split("/").length);
        }
        this.save(one);

        if (CollectionUtils.isNotEmpty(in.getApiIdList())) {
            saveMenuApiRelate(one.getId(), UserUtil.getUserId(), now, in.getApiIdList());
        }

        log.info("新增权限：{}，操作人：{}", in, user);

        return one;
    }

    private void saveMenuApiRelate(Long id, Long userId, Date now, List<Long> apiIdList) {

        List<AuthorityMenuApiRelateDO> list = apiIdList.stream().map(x -> {
            AuthorityMenuApiRelateDO relateDO = new AuthorityMenuApiRelateDO();
            relateDO.setId(IdGenUtil.get().nextId());
            relateDO.setApiId(x);
            relateDO.setMenuId(id);
            relateDO.setCreateTime(now);
            relateDO.setUpdateTime(now);
            relateDO.setCreateUserId(userId);
            relateDO.setUpdateUserId(userId);
            return relateDO;
        }).collect(Collectors.toList());
        menuApiRelateService.saveBatch(list);
    }

    @Override
    public GetMenuVO getMenu(Long id) {
        return this.getBaseMapper().getMenu(id);
    }

    @Override
    public AuthorityMenuDO updateMenu(UpdateMenuReqDTO in) {
        AuthorityMenuDO one = this.getById(in.getId());
        KingHoodExceptionUtil.isNull(one, "菜单不存在");

        if(Objects.equals(in.getStatus(),CommonConstants.DISABLE)){
            long hasSun = new LambdaQueryChainWrapper<>(this.getBaseMapper())
                    .eq(AuthorityMenuDO::getParentId, in.getId())
                    .eq(AuthorityMenuDO::getStatus, CommonConstants.ENABLE)
                    .eq(AuthorityMenuDO::getIsDelete, CommonConstants.IS_DELETE_N)
                    .count();
            KingHoodExceptionUtil.trueThrows(hasSun > 0, "存在启用状态的下级菜单，不允许停用");
        }
        if(Objects.equals(in.getStatus(),CommonConstants.ENABLE) && Objects.nonNull(one.getParentId())){
            long hasParent = new LambdaQueryChainWrapper<>(this.getBaseMapper())
                    .eq(AuthorityMenuDO::getId, one.getParentId())
                    .eq(AuthorityMenuDO::getStatus, CommonConstants.DISABLE)
                    .eq(AuthorityMenuDO::getIsDelete, CommonConstants.IS_DELETE_N)
                    .count();
            KingHoodExceptionUtil.trueThrows(hasParent > 0, "父菜单停用状态，请修改父菜单状态");
        }


        if (Objects.nonNull(in.getPermissionCode()) && !Objects.equals(in.getPermissionCode(), one.getPermissionCode())) {
            // 角色名字和code重复
            Wrappers.<AuthorityMenuDO>lambdaQuery().eq(AuthorityMenuDO::getId, in.getId());
            long count = new LambdaQueryChainWrapper<>(this.getBaseMapper())
                    .eq(AuthorityMenuDO::getIsDelete, CommonConstants.IS_DELETE_N)
                    .notIn(AuthorityMenuDO::getId, in.getId())
                    .eq(AuthorityMenuDO::getPermissionCode, in.getPermissionCode())
                    .count();
            KingHoodExceptionUtil.trueThrows(count > 0, "菜单的code已存在");
        }

        String idPath = null;
        if(Objects.nonNull(in.getParentId())){
            GetMenuVO parent = getMenu(in.getParentId());
            KingHoodExceptionUtil.isNull(parent,"父类不存在");
            idPath = parent.getIdPath();
            KingHoodExceptionUtil.isNull(idPath,"父类idPath存在异常");
        }

        BeanUtils.copyProperties(in, one);
        UserDTO user = UserUtil.getUser();
        Date now = new Date();
        one.setUpdateTime(now);
        one.setUpdateUserId(UserUtil.getUserId());
        if(idPath == null){
            one.setIdPath(one.getId().toString());
            one.setLevel(1);
        } else {
            one.setIdPath(idPath + "/" + one.getId().toString() );
            one.setLevel(one.getIdPath().split("/").length);
        }
        this.updateById(one);

        // 删除原来的绑定
        new LambdaUpdateChainWrapper<>(menuApiRelateService.getBaseMapper())
                .eq(AuthorityMenuApiRelateDO::getMenuId, in.getId())
                .remove();

        if (CollectionUtils.isNotEmpty(in.getApiIdList())) {
            saveMenuApiRelate(one.getId(), UserUtil.getUserId(), now, in.getApiIdList());
        }

        log.info("修改菜单：{}，操作人：{}", in, user);

        return one;
    }

    @Override
    public Boolean deleteMenu(List<Long> idList) {
        KingHoodExceptionUtil.isEmpty(idList, "请选择要删除的菜单");

        long enableCount = new LambdaQueryChainWrapper<>(this.getBaseMapper())
                .in(AuthorityMenuDO::getId, idList)
                .eq(AuthorityMenuDO::getStatus, CommonConstants.ENABLE)
                .eq(AuthorityMenuDO::getIsDelete, CommonConstants.IS_DELETE_N).count();
        KingHoodExceptionUtil.trueThrows(enableCount > 0, "启用状态不允许删除");

        long hasSun = new LambdaQueryChainWrapper<>(this.getBaseMapper())
                .in(AuthorityMenuDO::getParentId, idList)
                .eq(AuthorityMenuDO::getStatus, CommonConstants.ENABLE)
                .eq(AuthorityMenuDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .count();
        KingHoodExceptionUtil.trueThrows(hasSun > 0, "存在下级菜单不允许删除");

        long count = new LambdaQueryChainWrapper<>(menuApiRelateService.getBaseMapper())
                .in(AuthorityMenuApiRelateDO::getMenuId, idList)
                .eq(AuthorityMenuApiRelateDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .count();
        KingHoodExceptionUtil.trueThrows(count > 0, "菜单存在角色绑定，无法删除");

        boolean update = new LambdaUpdateChainWrapper<>(this.getBaseMapper())
                .in(AuthorityMenuDO::getId, idList)
                .set(AuthorityMenuDO::getIsDelete, CommonConstants.IS_DELETE_Y)
                .set(AuthorityMenuDO::getUpdateUserId, UserUtil.getUser().getId())
                .set(AuthorityMenuDO::getUpdateTime, new Date())
                .update();

        log.info("删除菜单：{}，结果：{}，操作人：{}", idList, update, UserUtil.getUser());
        return update;
    }

    /**
     * 代码来自定制
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean changeSort(SystemMenuDragReqDTO systemMenuDragReqDTO) {

        AuthorityMenuDO systemMenu = this.getById(systemMenuDragReqDTO.getId());
        List<AuthorityMenuDO> systemMenuListUpdate = new ArrayList<>();
        if (systemMenuDragReqDTO.getPid() != null) {
            LambdaQueryWrapper<AuthorityMenuDO> lambdaQueryWrapper = Wrappers.lambdaQuery();
            lambdaQueryWrapper.eq(AuthorityMenuDO::getParentId, systemMenuDragReqDTO.getPid())
                    .eq(AuthorityMenuDO::getStatus, CommonConstants.ENABLE)
                    .eq(AuthorityMenuDO::getIsDelete, CommonConstants.IS_DELETE_N);
            List<AuthorityMenuDO> systemMenuList = this.getBaseMapper().selectList(lambdaQueryWrapper);
            if (systemMenuDragReqDTO.getPid().equals(systemMenu.getParentId())) {//同级拖拽
                if (CollectionUtils.isNotEmpty(systemMenuList)) {
                    systemMenuList.forEach(item -> {
                        if (systemMenu.getSort().compareTo(systemMenuDragReqDTO.getSort()) > 0) {//从大移到小
                            if (systemMenuDragReqDTO.getSort().compareTo(item.getSort()) <= 0 && systemMenu.getSort().compareTo(item.getSort()) > 0) {
                                item.setSort(item.getSort() + 1);
                            }
                        } else if (systemMenu.getSort().compareTo(systemMenuDragReqDTO.getSort()) < 0) {//从小移到大
                            if (systemMenuDragReqDTO.getSort().compareTo(item.getSort()) >= 0 && systemMenu.getSort().compareTo(item.getSort()) < 0) {
                                item.setSort(item.getSort() - 1);
                            }
                        } else {
                            return;
                        }
                    });
                }
                systemMenuListUpdate.addAll(systemMenuList);
            } else {//跨级拖拽
                if (CollectionUtils.isNotEmpty(systemMenuList)) {
                    if (systemMenuDragReqDTO.getSort() != null) {
                        systemMenuList.forEach(item -> {
                            if (systemMenuDragReqDTO.getSort().compareTo(item.getSort()) <= 0) {
                                item.setSort(item.getSort() + 1);
                            }
                        });
                        systemMenuListUpdate.addAll(systemMenuList);
                    } else {//排序为空，则放到最后一个
                        //取之前子数据的最大的排序值，然后加在它后面
                        //获取num列表取最大值
                        List<Integer> sortList = systemMenuList.stream().map(AuthorityMenuDO::getSort).collect(Collectors.toList());
                        Integer maxNum = Collections.max(sortList);
                        systemMenuDragReqDTO.setSort(maxNum + 1);
                    }
                } else {
                    if (systemMenuDragReqDTO.getSort() == null) {
                        systemMenuDragReqDTO.setSort(1);//原来没有子数据，则排第一个
                    }
                }

                LambdaQueryWrapper<AuthorityMenuDO> lambdaQueryWrapperOld = Wrappers.lambdaQuery();
                lambdaQueryWrapperOld.eq(AuthorityMenuDO::getParentId, systemMenu.getParentId())
                        .eq(AuthorityMenuDO::getStatus, CommonConstants.ENABLE)
                        .eq(AuthorityMenuDO::getIsDelete, CommonConstants.IS_DELETE_N);
                List<AuthorityMenuDO> systemMenuListOld = this.getBaseMapper().selectList(lambdaQueryWrapperOld);
                if (CollectionUtils.isNotEmpty(systemMenuListOld)) {
                    systemMenuListOld.forEach(item -> {
                        if (systemMenu.getSort().compareTo(item.getSort()) < 0) {
                            item.setSort(item.getSort() - 1);
                        }
                    });
                    systemMenuListUpdate.addAll(systemMenuListOld);
                }
            }
        } else {//最顶一级的拖拽
            LambdaQueryWrapper<AuthorityMenuDO> lambdaQueryWrapper = Wrappers.lambdaQuery();
            lambdaQueryWrapper.isNull(AuthorityMenuDO::getParentId)
                    .eq(AuthorityMenuDO::getStatus, CommonConstants.ENABLE)
                    .eq(AuthorityMenuDO::getIsDelete, CommonConstants.IS_DELETE_N);
            List<AuthorityMenuDO> systemMenuList = this.getBaseMapper().selectList(lambdaQueryWrapper);

            if (systemMenu.getParentId() != null) {//跨级拖拽
                if (CollectionUtils.isNotEmpty(systemMenuList)) {
                    if (systemMenuDragReqDTO.getSort() != null) {
                        systemMenuList.forEach(item -> {
                            if (systemMenuDragReqDTO.getSort().compareTo(item.getSort()) <= 0) {
                                item.setSort(item.getSort() + 1);
                            }
                        });
                        systemMenuListUpdate.addAll(systemMenuList);
                    } else {//排序为空，则放到最后一个
                        //取之前子数据的最大的排序值，然后加在它后面
                        //获取num列表取最大值
                        List<Integer> sortList = systemMenuList.stream().map(AuthorityMenuDO::getSort).collect(Collectors.toList());
                        Integer maxNum = Collections.max(sortList);
                        systemMenuDragReqDTO.setSort(maxNum + 1);
                    }
                } else {
                    if (systemMenuDragReqDTO.getSort() == null) {
                        systemMenuDragReqDTO.setSort(1);//原来没有子数据，则排第一个
                    }
                }

                LambdaQueryWrapper<AuthorityMenuDO> lambdaQueryWrapperOld = Wrappers.lambdaQuery();
                lambdaQueryWrapperOld.eq(AuthorityMenuDO::getParentId, systemMenu.getParentId())
                        .eq(AuthorityMenuDO::getStatus, CommonConstants.ENABLE)
                        .eq(AuthorityMenuDO::getIsDelete, CommonConstants.IS_DELETE_N);
                List<AuthorityMenuDO> systemMenuListOld = this.getBaseMapper().selectList(lambdaQueryWrapperOld);
                if (CollectionUtils.isNotEmpty(systemMenuListOld)) {
                    systemMenuListOld.forEach(item -> {
                        if (systemMenu.getSort().compareTo(item.getSort()) < 0) {
                            item.setSort(item.getSort() - 1);
                        }
                    });
                    systemMenuListUpdate.addAll(systemMenuListOld);
                }
            } else {//同级拖拽
                if (CollectionUtils.isNotEmpty(systemMenuList)) {
                    systemMenuList.forEach(item -> {
                        if (systemMenu.getSort().compareTo(systemMenuDragReqDTO.getSort()) > 0) {//从大移到小
                            if (systemMenuDragReqDTO.getSort().compareTo(item.getSort()) <= 0 && systemMenu.getSort().compareTo(item.getSort()) > 0) {
                                item.setSort(item.getSort() + 1);
                            }
                        } else if (systemMenu.getSort().compareTo(systemMenuDragReqDTO.getSort()) < 0) {//从小移到大
                            if (systemMenuDragReqDTO.getSort().compareTo(item.getSort()) >= 0 && systemMenu.getSort().compareTo(item.getSort()) < 0) {
                                item.setSort(item.getSort() - 1);
                            }
                        } else {
                            return;
                        }
                    });
                }
                systemMenuListUpdate.addAll(systemMenuList);
            }
        }
        if (CollectionUtils.isNotEmpty(systemMenuListUpdate)) {
            this.saveOrUpdateBatch(systemMenuListUpdate);
        }
        UpdateWrapper<AuthorityMenuDO> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", systemMenuDragReqDTO.getId())
                .set("sort", systemMenuDragReqDTO.getSort())
                .set("pid", systemMenuDragReqDTO.getPid())
                .set("update_time", new Date());
        this.update(updateWrapper);
        return true;
    }

    @Override
    public List<AuthorityMenuDO> queryAllMenuList(QueryMenuListReqDTO in) {

        return new LambdaQueryChainWrapper<>(this.getBaseMapper())
                .eq(AuthorityMenuDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .eq(Objects.nonNull(in.getBelongType()),AuthorityMenuDO::getBelongType, in.getBelongType())
                .orderByAsc(AuthorityMenuDO::getLevel)
                .orderByAsc(AuthorityMenuDO::getSort)
                .orderByDesc(AuthorityMenuDO::getUpdateTime)
                .list();
    }

    @Override
    public List<AuthorityMenuDO> queryMenuListByUserId(QueryMenuListReqDTO in) {

        return this.getBaseMapper().queryMenuListByUserId(UserUtil.getUser().getId(),in);
    }
}
